﻿using System;

namespace Bettzueche.Dampfross
{
    /// <summary>
    /// Würfel-Koordinate bestehend aus 3 ganzzahligen Werten.
    /// Value-Type. Unterstützt die Operatoren +, -, *, ==, !=,
    /// </summary>
    public struct CubeKoordinate
    {
        public int X;

        public int Y;

        public int Z;

        /// <summary>
        /// Initialisiert eine neue <see cref="CubeKoordinate"/>-Struktur.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="y">The y.</param>
        /// <param name="z">The z.</param>
        public CubeKoordinate(int x, int y, int z) {
            X = x;
            Y = y;
            Z = z;
        }

        /// <summary>
        /// Gibt die Summe der drei Koordinatenwerte.
        /// </summary>
        /// <returns>Summe der drei Koordinatenwerte</returns>
        public int Sum() {
            return X+Y+Z;
        }

        /// <summary>
        /// Returns a <see cref="System.String" /> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String" /> that represents this instance.
        /// </returns>
        public override string ToString() {
            return string.Format("Cube({0}, {1}, {2})", X, Y, Z);
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj) {
            if (obj is CubeKoordinate) {
                var other = (CubeKoordinate)obj;
                return (this.X == other.X) && (this.Y == other.Y) && (this.Z == other.Z);
            }
            return false;
        }

        /// <summary>
        /// Determines whether the specified <see cref="Bettzueche.Dampfross.CubeKoordinate">CubeKoordinate</see>, is equal to this instance.
        /// </summary>
        /// <param name="coord">The <c>CubeKoordinate</c> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <c>CubeKoordinate</c> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public bool Equals(CubeKoordinate coord) {
            return (this.X == coord.X) && (this.Y == coord.Y) && (this.Z == coord.Z);
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
        /// </returns>
        public override int GetHashCode() {
            return ((13 * X) ^ (31 * Y)) ^ (5 * Z);
        }


        /// <summary>
        /// Implements the operator +. Komponentenweise Addition.
        /// </summary>
        /// <param name="a">Würfelkoordinate A</param>
        /// <param name="b">Würfelkoordinate  B</param>
        /// <returns>
        /// Neue <c>CubeCoordinate</c> mit komponentenweise addierten Werten.
        /// </returns>
        public static CubeKoordinate operator +(CubeKoordinate a, CubeKoordinate b) {
            return new CubeKoordinate(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
        }
        /// <summary>
        /// Implements the operator +. Komponentenweise Subtraktion.
        /// </summary>
        /// <param name="a">Würfelkoordinate A</param>
        /// <param name="b">Würfelkoordinate  B</param>
        /// <returns>
        /// Neue <c>CubeCoordinate</c> mit komponentenweise subtrahierten Werten.
        /// </returns>
        public static CubeKoordinate operator -(CubeKoordinate a, CubeKoordinate b) {
            return new CubeKoordinate(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
        }
        /// <summary>
        /// Implements the operator *.
        /// </summary>
        /// <param name="a">Würfel koordinate A.</param>
        /// <param name="scalar">The scalar.</param>
        /// <returns>
        /// Komponentenweise Skalarmultiplikation.
        /// </returns>
        public static CubeKoordinate operator *(CubeKoordinate a, int scalar) {
            return new CubeKoordinate(a.X * scalar, a.Y * scalar, a.Z * scalar);
        }
        /// <summary>
        /// Implements the operator *.
        /// </summary>
        /// <param name="a">Würfel koordinate A.</param>
        /// <param name="scalar">The scalar.</param>
        /// <returns>
        /// Komponentenweise Skalarmultiplikation.
        /// </returns>
        public static CubeKoordinate operator *(int scalar, CubeKoordinate a) {
            return new CubeKoordinate(a.X * scalar, a.Y * scalar, a.Z * scalar);
        }
        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="a">Würfelkoordinate A.</param>
        /// <param name="b">Würfelkoordinate B</param>
        /// <returns>
        /// true, if components pairwise equal.
        /// </returns>
        public static bool operator ==(CubeKoordinate a, CubeKoordinate b) {
            return (a.X == b.X) && (a.Y == b.Y) && (a.Z == b.Z);
        }
        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="a">Würfelkoordinate A.</param>
        /// <param name="b">Würfelkoordinate B</param>
        /// <returns>
        /// true, if at least one a-coordinate is not the same as the corresponding b-coordinate.
        /// </returns>
        public static bool operator !=(CubeKoordinate a, CubeKoordinate b) {
            return !((a.X == b.X) && (a.Y == b.Y) && (a.Z == b.Z));
        }
    }
}
